/**
 * 
 */
package ro.dta.idbi.model;

import java.util.Hashtable;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import ro.dta.idbi.interfaces.IPrimitiveParser;
import uk.ac.ic.doc.automed.IntegrityException;
import uk.ac.ic.doc.automed.NotFoundException;
import uk.ac.ic.doc.automed.reps.Schema;
import uk.ac.ic.doc.automed.reps.TypeMismatchException;

/**
 * Abstract class for primitive BAV transformations
 * 
 * @author Tudor Dobrila
 * 
 */
public abstract class AbstractPrimitivePattern extends AbstractPattern {

	/**
	 * Regular expression patterns
	 */
	protected Hashtable<String, Pattern> patterns;

	/**
	 * Parser for the constructs
	 */
	protected Hashtable<String, IPrimitiveParser> parsers;

	/**
	 * Construct being modified in current pattern
	 */
	protected Hashtable<String, Object> construct;

	/**
	 * Add a new construct class constructor
	 * 
	 * @param sourceSchema
	 *            Source schema over which the transformation is applied
	 * @param command
	 *            Name of the primitive BAV transformation
	 */
	public AbstractPrimitivePattern(final Schema sourceSchema, final String command)
			throws NotFoundException, IntegrityException {
		super(sourceSchema);

		parsers = new Hashtable<String, IPrimitiveParser>();
		parsers.put(command + "table", new AddTableParser());
		parsers.put(command + "column", new AddColumnParser());
		parsers.put(command + "primarykey", new AddPkParser());
		parsers.put(command + "foreignkey", new AddFkParser());
		pattern = Pattern
				.compile("^((add)|(delete)|(extend)|(contract)|(rename))[ ]*\\(([^:]+):[^\\)]+\\)$");
		if ("rename".equals(command)) {
			patterns = Utils.constructRenamePatterns();
		} else {
			patterns = Utils.constructPatterns(command);
		}
	}

	/**
	 * Add a new construct class constructor
	 * 
	 * @param sourceSchema
	 *            Name of source schema over which the transformation is applied
	 * @param command
	 *            Name of the primitive BAV transformation
	 */
	public AbstractPrimitivePattern(final String sourceSchema, final String command)
			throws NotFoundException, IntegrityException {
		this(Schema.getSchema(sourceSchema), command);
	}

	@Override
	public boolean check(String trans) {
		Matcher matcher = pattern.matcher(trans);

		if (matcher.matches()) {
			String command = matcher.group(1);
			String name = matcher.group(7);
			if (patterns.containsKey(command + name)) {
				Pattern p = patterns.get(command + name);
				return p.matcher(trans).matches();
			}
		}

		return false;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see ro.dta.idbi.model.AbstractPattern#parse(java.lang.String)
	 */
	@Override
	protected void parse(String trans) {
		Matcher matcher = pattern.matcher(trans);

		if (matcher.matches()) {
			String command = matcher.group(1);
			String name = matcher.group(7);
			if (patterns.containsKey(command + name)) {
				Matcher matcher2 = patterns.get(command + name).matcher(trans);
				matcher2.find();
				construct = parsers.get(command + name).parse(matcher2);
			}
		}
	}

	/**
	 * Get the reverse transformation of a primitive BAV command
	 * 
	 * @param command
	 *            Primitive BAV command
	 * @return Reverse transformation of the BAV command
	 */
	public static String getReverseTrans(String command) {
		final int bracket = command.trim().indexOf('(');
		if (bracket != -1) {
			final String name = command.substring(0, bracket).trim();
			final String body = command.substring(bracket);

			if ("add".equals(name)) {
				return "delete " + body;
			} else if ("delete".equals(name)) {
				return "add " + body;
			} else if ("rename".equals(name)) {
				return "rename " + body;
			}
		}

		return null;
	}

	@Override
	protected List<String> getPrimitiveCommands() {
		// No primitive commands for primitive BAV transformations
		return null;
	}

	@Override
	protected boolean verify() {
		return true;
	}

	@Override
	public Schema execute(String trans) throws NotFoundException, TypeMismatchException,
			IntegrityException {
		if (!check(trans)) {
			throw new IllegalArgumentException("Command is invalid.");
		}
		this.parse(trans);

		return null;
	}

}
